// Copyright (C) 1953-2020 NUDT
// Verilog module name - ctag_and_rtag_add
// Version: V3.4.0.20220404
// Created:
//         by - fenglin 
////////////////////////////////////////////////////////////////////////////
// Description:
///////////////////////////////////////////////////////////////////////////

`timescale 1ns/1ps

module frame_modify
(
       i_clk               ,
       i_rst_n             ,

       i_add_tag_flag      ,
       iv_ipv              ,
       iv_flowid           ,
       i_replication_flag  ,
       iv_seq_num          ,
       iv_inject_dbufid    ,
       
       iv_data             ,
       i_data_wr           ,
           
       ov_data,       
       o_data_wr ,  
       ov_ipv  ,     
       ov_inject_dbufid         
);

// I/O
// clk & rst
input                  i_clk;                   //125Mhz
input                  i_rst_n;
//input
input                  i_add_tag_flag;
input      [2:0]       iv_ipv;
input      [13:0]      iv_flowid;
input                  i_replication_flag;
input      [15:0]      iv_seq_num;
input      [4:0]       iv_inject_dbufid;

input      [8:0]       iv_data;
input                  i_data_wr;

output reg  [8:0]      ov_data;
output reg             o_data_wr;
output reg  [2:0]      ov_ipv;
output reg  [4:0]      ov_inject_dbufid;

reg         [89:0]     rv_shift_data;
reg         [9:0]      rv_shift_data_valid;
always @(posedge i_clk or negedge i_rst_n) begin
    if(i_rst_n == 1'b0)begin                                 
        rv_shift_data           <= 90'b0  ;
        rv_shift_data_valid     <= 10'b0  ;
    end
    else begin
        if(i_data_wr)begin
            rv_shift_data       <= {rv_shift_data[80:0],iv_data};
            rv_shift_data_valid <= {rv_shift_data_valid[8:0],i_data_wr};
        end
        else begin
            rv_shift_data       <= {rv_shift_data[80:0],9'b0};
            rv_shift_data_valid <= {rv_shift_data_valid[8:0],1'b0};        
        end
    end
end
////////////////////////////////////////
//        save pkt data in register   //
////////////////////////////////////////
reg                    r_add_tag_flag     ;
reg        [13:0]      rv_flowid          ;
reg                    r_replication_flag ;
reg        [15:0]      rv_seq_num         ;
//reg        [4:0]       rv_inject_dbufid;

(*MARK_DEBUG="true"*)reg        [11:0]      rv_pkt_cycle_cnt; 

(*MARK_DEBUG="true"*)reg        [3:0]        fmo_state;         
localparam              IDLE_S                     = 3'd0,
                        TRANSMIT_MAC_S             = 3'd1,
                        TRANSMIT_TAG_S             = 3'd2,
                        TRANSMIT_CTAG_REMAINS_S    = 3'd3,
                        TRANSMIT_RTAG_REMAINS_S    = 3'd4,
                        TRANSMIT_PKT_S             = 3'd5;

always @(posedge i_clk or negedge i_rst_n) begin
    if(i_rst_n == 1'b0)begin
        r_add_tag_flag          <= 1'b0  ;
        rv_flowid               <= 14'b0 ;
        r_replication_flag      <= 1'b0  ;
        rv_seq_num              <= 16'b0 ;
         //rv_inject_dbufid        <= 5'b0  ;                                
        ov_data                 <= 69'b0  ;
        o_data_wr               <= 1'b0  ;
        ov_ipv                  <= 3'b0  ;
        ov_inject_dbufid        <= 5'b0  ;
                                         
        rv_pkt_cycle_cnt        <= 12'b0 ; 

        fmo_state               <= IDLE_S;
    end
    else begin
        case(fmo_state)
            IDLE_S:begin        
                if((i_data_wr== 1'b1)&&(iv_data[8] == 1'b1))begin//first byte
                    r_add_tag_flag          <= i_add_tag_flag      ;
                    rv_flowid               <= iv_flowid           ;
                    r_replication_flag      <= i_replication_flag  ;
                    rv_seq_num              <= iv_seq_num          ;
                     //rv_inject_dbufid        <= iv_inject_dbufid    ;                                              
                    ov_ipv                  <= iv_ipv              ;
                    ov_inject_dbufid        <= iv_inject_dbufid    ; 
                    
                    ov_data                 <= iv_data; 
                    o_data_wr               <= i_data_wr; 

                    rv_pkt_cycle_cnt        <= 12'd1 ;                     
                    if(i_add_tag_flag)begin                                                  
                        fmo_state           <= TRANSMIT_MAC_S;
                    end                     
                    else begin                                                         
                        fmo_state           <= TRANSMIT_PKT_S;
                    end
                end           
                else begin
                    r_add_tag_flag          <= 1'b0  ;
                    rv_flowid               <= 14'b0 ;
                    r_replication_flag      <= 1'b0  ;
                    rv_seq_num              <= 16'b0 ;
                    //rv_inject_dbufid        <= 5'b0    ;                                 
                    ov_data                 <= 9'b0  ;
                    o_data_wr               <= 1'b0  ;
                    ov_ipv                  <= 3'b0  ;
                    ov_inject_dbufid        <= 5'b0  ;
                                                     
                    rv_pkt_cycle_cnt        <= 12'b0 ; 

                    fmo_state               <= IDLE_S;             
                end
            end
            TRANSMIT_MAC_S:begin
                rv_pkt_cycle_cnt        <= rv_pkt_cycle_cnt+ 1'b1; 
                
                ov_data                 <= iv_data; 
                o_data_wr               <= i_data_wr;                     
                if(rv_pkt_cycle_cnt==12'd11)begin
                    fmo_state           <= TRANSMIT_TAG_S;  
                end
                else begin
                    fmo_state           <= TRANSMIT_MAC_S;
                end                
            end
            TRANSMIT_TAG_S:begin
                rv_pkt_cycle_cnt        <= rv_pkt_cycle_cnt+ 1'b1; 
                                   
                if(rv_pkt_cycle_cnt == 12'd12)begin//c-tag
                    ov_data                 <= {1'b0,8'h81}; 
                    o_data_wr               <= 1'b1;   
                end
                else if(rv_pkt_cycle_cnt == 12'd13)begin//c-tag
                    ov_data                 <= {1'b0,8'h00}; 
                    o_data_wr               <= 1'b1;   
                end
                else if(rv_pkt_cycle_cnt == 12'd14)begin//c-tag
                    ov_data[8]              <= 1'b0;
                    ov_data[7]              <= r_replication_flag;
                    if(ov_ipv >= 3'd5)begin
                        ov_data[6]              <= 1'b0;//st
                    end
                    else if(ov_ipv >= 3'd3)begin
                        ov_data[6]              <= 1'b1;//rc
                    end
                    else begin
                        ov_data[6]              <= 1'b1;//rc
                    end
                    ov_data[5:0]             <= rv_flowid[13:8];
                    o_data_wr                <= 1'b1;   
                end
                else if(rv_pkt_cycle_cnt == 12'd15)begin//c-tag
                    ov_data                 <= {1'b0,rv_flowid[7:0]};
                    o_data_wr               <= 1'b1; 
                    if(r_replication_flag)begin//replication
                        fmo_state           <= TRANSMIT_TAG_S;
                    end
                    else begin
                        fmo_state           <= TRANSMIT_CTAG_REMAINS_S;
                    end                    
                end 
                else if(rv_pkt_cycle_cnt == 12'd16)begin//r-tag
                    ov_data                 <= {1'b0,8'hf1};
                    o_data_wr               <= 1'b1;   
                end
                else if(rv_pkt_cycle_cnt == 12'd17)begin//r-tag
                    ov_data                 <= {1'b0,8'hc1};
                    o_data_wr               <= 1'b1;   
                end
                else if(rv_pkt_cycle_cnt == 12'd18)begin//r-tag
                    ov_data                 <= {1'b0,8'h00};
                    o_data_wr               <= 1'b1;   
                end
                else if(rv_pkt_cycle_cnt == 12'd19)begin//r-tag
                    //ov_data                 <= {1'b0,3'h0,rv_inject_dbufid};
					ov_data                 <= {1'b0,8'h0};
                    o_data_wr               <= 1'b1;   
                end
                else if(rv_pkt_cycle_cnt == 12'd20)begin//r-tag
                    ov_data                 <= {1'b0,rv_seq_num[15:8]};
                    o_data_wr               <= 1'b1;   
                end 
                else if(rv_pkt_cycle_cnt == 12'd21)begin//r-tag
                    ov_data                 <= {1'b0,rv_seq_num[7:0]};
                    o_data_wr               <= 1'b1; 
                    fmo_state               <= TRANSMIT_RTAG_REMAINS_S;                   
                end                 
                else begin
                    fmo_state           <= TRANSMIT_TAG_S;
                end                
            end
            TRANSMIT_CTAG_REMAINS_S:begin
                o_data_wr         <= rv_shift_data_valid[3];
                ov_data           <= rv_shift_data[35:27];
                rv_pkt_cycle_cnt  <= 12'b0;
                if(rv_shift_data_valid[3] && rv_shift_data[35])begin
                    fmo_state     <= IDLE_S;           
                end
                else begin
                    fmo_state     <= TRANSMIT_CTAG_REMAINS_S;
                end            
            end            
            TRANSMIT_RTAG_REMAINS_S:begin
                o_data_wr         <= rv_shift_data_valid[9];
                ov_data           <= rv_shift_data[89:81];
                rv_pkt_cycle_cnt  <= 12'b0;
                if(rv_shift_data_valid[9] && rv_shift_data[89])begin
                    fmo_state     <= IDLE_S;           
                end
                else begin
                    fmo_state     <= TRANSMIT_RTAG_REMAINS_S;
                end            
            end            
            TRANSMIT_PKT_S:begin
                o_data_wr         <= i_data_wr;
                ov_data           <= iv_data;
                rv_pkt_cycle_cnt  <= 12'b0;
                if(i_data_wr && iv_data[8])begin
                    fmo_state     <= IDLE_S;           
                end
                else begin
                    fmo_state     <= TRANSMIT_PKT_S;
                end            
            end            
            default:begin
                rv_pkt_cycle_cnt  <= 12'b0;
                ov_data           <= 9'b0;
                o_data_wr         <= 1'b0;
                fmo_state         <= IDLE_S;            
            end            
        endcase    
     end
end
endmodule